#ifndef __FIBER_H__
#define __FIBER_H__

#include <ucontext.h>
#include <memory>
#include <functional>


namespace sylar
{

 /* ***************************************************************************************************************
*   man page 详见
*   int getcontext(ucontext_t *ucp);                     获取当前上下文
*   int setcontext(const ucontext_t *ucp);               设置当上下文
*   void makecontext(ucontext_t *ucp, void (*func)(), int argc, ...);       创建一个新的协程在某个函数上面执行
*   int swapcontext(ucontext_t *oucp, const ucontext_t *ucp);   将一个协程设置到（切换）另一个协程（set get/set make组合）
*   int swapcontext(ucontext_t *__restrict__ __oucp, const ucontext_t *__restrict__ __ucp) 上下文切换
*   
*****************************************************************************************************************/

/* *****************************************************************************
* 通过 mian协程控制子协程 
* 线程通过主协程调度子协程，子协程执行完回到主协程
* thread----> main协程   <=========> 创新子协程
* 每个线程都有一个主协程
===============================================================================

新理解： main协程是正在运行的协程，通过协程的切换将子协程切换成主协程 ???????????????????????

******************************************************************************/



class Scheduler;

// 当作智能指针 继承 enable_shared_from_this的类不能再栈上创建
class Fiber : public std::enable_shared_from_this<Fiber>
{

friend class Scheduler;

public:
    using ptr = std::shared_ptr<Fiber>;

    // 定义状态
    enum State
    {
        INIT,       // 初始化
        HOLD,       // 挂起 暂停状态
        EXEC,       // 正在执行
        TERM,       // 结束状态
        READY,      // 可执行状态
        EXCEPT,      // 异常状态
    };

public:
    Fiber(std::function<void()> cb, int stacksize = 0, bool user_caller = false);
    ~Fiber();

    // 当协程执行完了可以重置函数并重置状态，函数执行完但是内存还在
    // INIT / TERM 才能执行
    void reset(std::function<void()> cb);

    // 切换
    // void call();

    // 切换到当前协程执行
    void swapIn();  
    // 切换到后台 协程让出
    void swapOut(); 
    // 强行将当前协程换成目标协程
    void call();

    void back();

    uint64_t getId() const { return m_id; }

    const State getState() const { return m_state; }

public:

    // 设置当前
    static void SetThis(Fiber* f);
    // 返回当前执行点的协程
    static Fiber::ptr GetThis(); 
    // 协程切换后台 并 设置 状态
    static void YaildToReady();
    static void YaildToHold();

    // 总的协程数量
    static uint64_t TotalFibers(); 
    // 运行函数
    static void MainFunc();
    static void CallerMainFunc();

    static uint64_t GetFiberId();

private:
    Fiber();

private:

    uint64_t m_id = 0;              // 协程id
    uint32_t m_stacksize = 0;       // 栈大小
    State m_state = INIT;            // 协程状态

    ucontext_t m_ctx;               // 
    void* m_stack = nullptr;        // 栈的地址空间

    std::function<void()> m_cb;     // 执行方法
};




    
}

#endif